package com.csx.governance.traffic.adapter.outbound.resttemplate;

import com.csx.governance.traffic.core.context.*;
import com.csx.governance.traffic.core.context.resttemplate.TrafficRestTemplateRequest;
import com.csx.governance.traffic.core.context.resttemplate.TrafficRestTemplateResponse;
import com.csx.governance.traffic.core.interceptor.TrafficHandlerInterceptorRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;

import java.io.IOException;

/**
 * traffic 流量出口 - 适配RestTemplate方式外调
 * @author cuisongxu
 * @date 2023/3/18 15:36
 */
public class TrafficRestTemplateInterceptor implements ClientHttpRequestInterceptor {

    private final Logger logger = LoggerFactory.getLogger(TrafficRestTemplateInterceptor.class);

    private final TrafficHandlerInterceptorRunner handlerInterceptorRunner;

    public TrafficRestTemplateInterceptor(TrafficHandlerInterceptorRunner handlerInterceptorRunner) {
        this.handlerInterceptorRunner = handlerInterceptorRunner;
    }

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {

        TrafficRestTemplateRequest trafficRestTemplateRequest = new TrafficRestTemplateRequest(request);
        TrafficRestTemplateResponse trafficRestTemplateResponse = null;
        ClientHttpResponse response;
        Exception ex = null;
        // 构造请求上下文
        buildContext(trafficRestTemplateRequest);
        try {
            handlerInterceptorRunner.preHandle(trafficRestTemplateRequest, null);
            response = execution.execute(trafficRestTemplateRequest, body);
            trafficRestTemplateResponse = new TrafficRestTemplateResponse(response);
            handlerInterceptorRunner.postHandle(trafficRestTemplateRequest, trafficRestTemplateResponse);
            return response;
        }catch (Exception e) {
            ex = e;
            logger.error("TrafficRestTemplateInterceptor interceptor error because: {}", e.getMessage());
            throw e;
        }finally {
            handlerInterceptorRunner.afterCompletion(trafficRestTemplateRequest, trafficRestTemplateResponse, ex);
        }
    }
    private void buildContext(TrafficRequest request) {
        TrafficContext context = TrafficContextHolder.getContext();
        if(context != null) {
            context.setSubRequest(request);
        } else { // 说明是由内部定时任务发起的外调，而不是由入栈请求导致的外调
            TrafficInternalContexts.set(request);
        }
    }
}
